package compiler.parser.lalr;

import java.util.HashSet;
import java.util.Set;

/// <summary>
/// Summary description for LALRState.
/// </summary>
public class LALRState
{
    //~ Static fields/initializers ---------------------------------------------

    protected static int NEXT_ID = 0; // id used in creating the

    //~ Instance fields --------------------------------------------------------

    // unique items is the items with the same production & dot
    // this is the expansion of the kernel
    private Set<LALRItem> items = new HashSet<LALRItem>();

    // subset of lalr_item_set. used to compare states (this is the "unexapnded" core)
    private Set<LALRItem> kernel = new HashSet<LALRItem>();

    // items uniqueness is the symbol to trans on
    private Set<LALRTransition> transitions = new HashSet<LALRTransition>();
    private boolean             reduceReduceConflict = false;
    private boolean             sealed = false;
    private boolean             shiftReduceConflict = false;
    private int                 id; // the next id to be assigned

    //~ Constructors -----------------------------------------------------------

    public LALRState(boolean realState)
    {
        // used to support temp LALRStates
        if (realState)
            id = NEXT_ID++;
    }

    //~ Methods ----------------------------------------------------------------

    public static void reset()
    {
        NEXT_ID = 0;
    }

    public void addLALRItem(LALRItem item)
    {
        if (sealed)
        {
            System.out.println("ERR: adding item to a seal LALRState");

            return;
        }

        items.add(item);
        kernel.add(item);
    }

    // compares the kernels
    @Override
    public boolean equals(Object obj)
    {
        if ((obj == null) || (getClass() != obj.getClass()))
        {
            return false;
        }

        return kernel.equals(((LALRState)obj).kernel);
    }

    public int getId()
    {
        return id;
    }

    public Set<LALRItem> getItems()
    {
        return items;
    }

    public Set<LALRItem> getKernel()
    {
        return kernel;
    }

    public Set<LALRTransition> getTransitions()
    {
        return transitions;
    }

    @Override
    public int hashCode()
    {
        return kernel.hashCode();
    }

    public boolean isReduceReduceConflict()
    {
        return reduceReduceConflict;
    }

    public boolean isSealed()
    {
        return sealed;
    }

    public boolean isShiftReduceConflict()
    {
        return shiftReduceConflict;
    }

    public void setReduceReduceConflict()
    {
        reduceReduceConflict = true;
    }

    // used to close adding
    public void setSealed()
    {
        sealed = true;
    }

    public void setShiftReduceConflict()
    {
        shiftReduceConflict = true;
    }

    public String toHTML()
    {
        StringBuilder html = new StringBuilder();
        html.append("<table BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"4\">\n");

        html.append("<tr>\n");
        html.append("<td>State " + id + "</td><td>LA</td>");
        html.append("</tr>\n");

        if (shiftReduceConflict)
        {
            html.append("\t" + "[[[[Shift-Reduce conflict !!!!]]]]\n");
        }

        if (reduceReduceConflict)
        {
            html.append("\t" + "[[[[Reduce-Reduce conflict !!!!]]]]\n");
        }

        for (LALRItem itm : items)
        {
            html.append("<tr>\n");
            html.append(itm.toHTML());
            html.append("</tr>\n");
        }

        html.append("</table>\n");

        return html.toString();
    }

    @Override
    public String toString()
    {
        StringBuilder str = new StringBuilder();

        if (shiftReduceConflict)
        {
            str.append("\t" + "[[[[Shift-Reduce conflict !!!!]]]]\n");
        }

        if (reduceReduceConflict)
        {
            str.append("\t" + "[[[[Reduce-Reduce conflict !!!!]]]]\n");
        }

        for (LALRItem itm : items)
        {
            str.append("\t" + itm.toString());
        }

        return str.toString();
    }
}
